package test.demos.ireport.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.FileUtils;

import org.apache.log4j.lf5.util.StreamUtils;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HeaderFooter;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleHtmlReportConfiguration;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimplePdfReportConfiguration;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
import net.sf.jasperreports.export.SimpleXlsReportConfiguration;

public class ReportUtil {

	private static final Logger log = LoggerFactory.getLogger(ReportUtil.class);

//	static {
//		FontFactory.register("fonts/Mhei_Medium/MSMHei.ttf", "Mhei-Medium");
//	}

	public static void generateWord(JasperDesign jasperDesign, JRDataSource dataSource, Map<String, Object> parameters,
			String wordFileName) {
		FileOutputStream outputStream = null;
		try {
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
			List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
			jasperPrintList.add(jasperPrint);
			File wordFile = new File(wordFileName);
			outputStream = new FileOutputStream(wordFile);
			JRRtfExporter exporter = new JRRtfExporter();

			exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
			exporter.setExporterOutput(new SimpleWriterExporterOutput(outputStream));

			exporter.exportReport();
		} catch (JRException jre) {
			log.error("[generateWord] JRException:" + jre.getMessage());
		} catch (IOException ioe) {
			log.error("[generateWord] IOException:" + ioe.getMessage());
		} catch (Exception e) {
			log.error("[generateWord] IOException:" + e.getMessage());
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {

				}
			}
		}
	}

	public static byte[] generatePDF(JasperDesign jasperDesign, JRDataSource dataSource, Map<String, Object> parameters,
			String pdfFileName) {
		FileOutputStream outputStream = null;
		byte bytes[] = null;
		try {
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); 
			File pdfFile = new File(pdfFileName);
			outputStream = new FileOutputStream(pdfFile);
			bytes = JasperRunManager.runReportToPdf(jasperReport, parameters, dataSource);
			outputStream.write(bytes, 0, bytes.length);
		} catch (JRException jre) {
			jre.printStackTrace();
			log.error("[Exception]: ", jre);
		} catch (IOException ioe) {
			ioe.printStackTrace();
			log.error("[Exception]: ", ioe);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("[Exception]: ", e);
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {

				}
			}
		}
		return bytes;
	}

	public static byte[] generatePDFByJasperFile(File jasperfile, JRDataSource dataSource,
			Map<String, Object> parameters, String pdfFileName) {
		FileOutputStream outputStream = null;
		byte bytes[] = null;
		try {
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(jasperfile);
			File pdfFile = new File(pdfFileName);
			outputStream = new FileOutputStream(pdfFile);
			bytes = JasperRunManager.runReportToPdf(jasperReport, parameters, dataSource);
			outputStream.write(bytes, 0, bytes.length);
		} catch (JRException jre) {
			log.error("[Exception]: ", jre);
		} catch (IOException ioe) {
			log.error("[Exception]: ", ioe);
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {

				}
			}
		}
		return bytes;
	}

	// Generate PDF in memory
	public static byte[] generatePDFinMemory(JasperDesign jasperDesign, JRDataSource dataSource,
			Map<String, Object> parameters) {
		byte bytes[] = null;
		try {
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
			bytes = JasperRunManager.runReportToPdf(jasperReport, parameters, dataSource);
		} catch (JRException jre) {
			log.error("[generateExcel] JRException:" + jre.getMessage());
		}
		return bytes;
	}

	public static void generateExcel(JasperDesign jasperDesign, JRDataSource dataSource, Map<String, Object> parameters,
			String excelFileName) {
		FileOutputStream outputStream = null;
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		ByteArrayOutputStream outputbos = new ByteArrayOutputStream();
		if (parameters == null) {
			parameters = new HashMap<String, Object>();
		}
		parameters.put("IS_IGNORE_PAGINATION", true);
		try {
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
			File excelFile = new File(excelFileName);
			outputStream = new FileOutputStream(excelFile);
			JRXlsExporter exporter = new JRXlsExporter();
			parameters.put(JRParameter.IS_IGNORE_PAGINATION, true);

			exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
			exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));

			SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
			configuration.setIgnorePageMargins(true);
			configuration.setRemoveEmptySpaceBetweenColumns(true);
			configuration.setRemoveEmptySpaceBetweenRows(true);
			configuration.setWhitePageBackground(false);
			configuration.setDetectCellType(true);
			configuration.setCollapseRowSpan(true);
			exporter.setConfiguration(configuration);

			exporter.exportReport();

			InputStream fileInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
			Workbook workbook = new HSSFWorkbook(fileInputStream);
			Sheet s = workbook.getSheetAt(0);
			PrintSetup hps = s.getPrintSetup();

			s.setAutobreaks(true);
			s.getFooter().setCenter("Page " + HeaderFooter.page() + " of " + HeaderFooter.numPages());
			hps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);
			hps.setFitWidth((short) 1);
			hps.setFitHeight((short) 0);
			hps.setFooterMargin(0);

			s.setMargin(HSSFSheet.LeftMargin, 0.4);
			s.setMargin(HSSFSheet.RightMargin, 0.4);
			s.setMargin(HSSFSheet.TopMargin, 0.4);
			s.setMargin(HSSFSheet.BottomMargin, 0.4);
			workbook.write(outputbos);

			outputbos.writeTo(outputStream);

		} catch (JRException jre) {
			log.error("[generateExcel] JRException:" + jre.getMessage());
		} catch (IOException ioe) {
			log.error("[generateExcel] IOException:" + ioe.getMessage());
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {
					log.info("[generateExcel] IOException:" + e.getMessage());
				}
			}
		}
	}

	// Generate Excel in memory
	public static byte[] generateExcelinMemory(JasperDesign jasperDesign, JRDataSource dataSource,
			Map<String, Object> parameters) {
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		ByteArrayOutputStream outputbos = new ByteArrayOutputStream();
		try {
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
			JRXlsExporter exporter = new JRXlsExporter();
			parameters.put(JRParameter.IS_IGNORE_PAGINATION, true);

			exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
			exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));

			SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();

			configuration.setRemoveEmptySpaceBetweenColumns(true);
			configuration.setRemoveEmptySpaceBetweenRows(true);
			configuration.setWhitePageBackground(false);
			configuration.setDetectCellType(true);
			exporter.setConfiguration(configuration);

			exporter.exportReport();

			InputStream fileInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
			Workbook workbook = new HSSFWorkbook(fileInputStream);
			Sheet s = workbook.getSheetAt(0);
			PrintSetup hps = s.getPrintSetup();

			s.setAutobreaks(true);
			s.getFooter().setCenter("Page " + HeaderFooter.page() + " of " + HeaderFooter.numPages());

			hps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);
			hps.setFitWidth((short) 1);
			hps.setFitHeight((short) 0);
			hps.setFooterMargin(0);

			s.setMargin(HSSFSheet.LeftMargin, 0.4);
			s.setMargin(HSSFSheet.RightMargin, 0.4);
			s.setMargin(HSSFSheet.TopMargin, 0.4);
			s.setMargin(HSSFSheet.BottomMargin, 0.4);
			workbook.write(outputbos);

		} catch (JRException jre) {
			log.error("[generateExcel] JRException:" + jre.getMessage());
		} catch (IOException ioe) {
			log.error("[generateExcel] IOException:" + ioe.getMessage());
		} finally {

			try {
				if (outputbos != null) {
					outputbos.flush();
					outputbos.close();
				}

				if (byteArrayOutputStream != null) {
					byteArrayOutputStream.flush();
					byteArrayOutputStream.close();
				}
			} catch (IOException e) {
				log.info("[generateExcel] IOException:" + e.getMessage());
			}
		}
		return outputbos.toByteArray();
	}

	public static void generateHTML(JasperDesign jasperDesign, JRDataSource dataSource, Map<String, Object> parameters,
			String htmlFileName) {
		FileOutputStream outputStream = null;
		try {
			log.info("jasperDesign:" + jasperDesign);
			JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
			log.info("jasperReport:" + jasperReport);
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
			log.info("jasperPrint:" + jasperPrint);
			HtmlExporter exporter = new HtmlExporter();
			File htmlFile = new File(htmlFileName);
			outputStream = new FileOutputStream(htmlFile);

			exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
			exporter.setExporterOutput(new SimpleHtmlExporterOutput(outputStream));

			SimpleHtmlReportConfiguration configuration = new SimpleHtmlReportConfiguration();
			exporter.setConfiguration(configuration);

			exporter.exportReport();
		} catch (JRException jre) {
			log.error("[generateHTML] JRException:" + jre.getMessage());
		} catch (IOException ioe) {
			log.error("[generateHTML] IOException:" + ioe.getMessage());
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {

				}
			}
		}

	}

	// for Concatenate several reports into the same PDF.
	public static void generateSeveralReportsIntoPDF(List<JasperPrint> jasperPrintList, String pdfFileName) {
		FileOutputStream outputStream = null;
		log.debug("[generateSeveralReportsIntoPDF] jasperPrintList.size= " + jasperPrintList.size());
		try {
			File pdfFile = new File(pdfFileName);
			outputStream = new FileOutputStream(pdfFile);
			JRPdfExporter exporter = new JRPdfExporter();

			exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
			exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));

			SimplePdfReportConfiguration configuration = new SimplePdfReportConfiguration();
			exporter.setConfiguration(configuration);

			exporter.exportReport();
		} catch (JRException jre) {
			log.error("[generateSeveralReportsIntoPDF] JRException:" + jre.getMessage());
		} catch (IOException ioe) {
			log.error("[generateSeveralReportsIntoPDF] IOException:" + ioe.getMessage());
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {

				}
			}
		}
	}

	// for Concatenate several reports into the same Excel.
	public static void generateSeveralReportsIntoExcel(List<JasperPrint> jasperPrintList, String xlsFileName)
			throws Exception {
		FileOutputStream outputStream = null;
		log.debug("[generateSeveralReportsIntoXsl] jasperPrintList.size= " + jasperPrintList.size());
		try {
			File pdfFile = new File(xlsFileName);
			FileUtils.forceMkdir(new File(xlsFileName.substring(0, xlsFileName.lastIndexOf("/"))));

			outputStream = new FileOutputStream(pdfFile);
			JRXlsExporter exporter = new JRXlsExporter();

			exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
			exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));

			SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
			configuration.setIgnorePageMargins(true);
			configuration.setRemoveEmptySpaceBetweenColumns(true);
			configuration.setRemoveEmptySpaceBetweenRows(true);
			configuration.setWhitePageBackground(false);
			// configuration.setColumnWidthRatio(1.3f);
			configuration.setCollapseRowSpan(true);
			exporter.setConfiguration(configuration);

			exporter.exportReport();
		} catch (JRException jre) {
			log.error("[generateSeveralReportsIntoXsl] JRException:" + jre.getMessage());
			throw jre;
		} catch (IOException ioe) {
			log.error("[generateSeveralReportsIntoXsl] IOException:" + ioe.getMessage());
			throw ioe;
		} finally {
			if (outputStream != null) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {
					throw e;
				}
			}
		}
	}

	public static Map<String, byte[]> unzipToByteArray(byte[] template) throws Exception {

		ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(template));
		Map<String, byte[]> fileMap = new HashMap<String, byte[]>();
		if (zis.available() > 0) {
			ZipEntry ze = zis.getNextEntry();

			while (ze != null) {
				byte[] unzipedByteArray = null;
				if (ze.getName().toUpperCase().endsWith(".JASPER")) {

					ByteArrayOutputStream baos = new ByteArrayOutputStream();

					byte[] buffer = new byte[1024];
					int len;
					while ((len = zis.read(buffer)) > -1) {
						baos.write(buffer, 0, len);
					}
					baos.flush();

					unzipedByteArray = baos.toByteArray();
					fileMap.put(ze.getName(), unzipedByteArray);
				} else {
					unzipedByteArray = StreamUtils.getBytes(zis);
					fileMap.put(ze.getName(), unzipedByteArray);
				}

				ze = zis.getNextEntry();
			}
		}
		return fileMap;
	}
}
